
import cn.hutool.core.swing.RobotUtil;
import cn.hutool.core.util.ObjectUtil;
import java.awt.AWTException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v107.network.Network;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.time.Duration;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import ru.yandex.qatools.ashot.AShot;
import ru.yandex.qatools.ashot.shooting.ShootingStrategies;

public class ScreenRobot {

  //下载路径
  public static final String dirPath = "D:\\ChromeDown\\downloadimage";
  //保存路径
  public static final String outFile = "D:\\ChromeDown\\downloadimage\\妖神记\\";

  /**
   * 《妖神记》
   *
   * @param args
   * @throws InterruptedException
   */
  public static void main(String[] args) throws InterruptedException, IOException, AWTException {
    //设置驱动参数信息
    WebDriver webDriver = new ChromeDriver(chromeOptions());
    //AShot截图
    responseAsImage2(webDriver, 55, 55, 10, ".png", 10);
    Thread.sleep(2000);
    webDriver.quit();
    webDriver.close();
  }

  /**
   * AShot截图
   *
   * @param driver 驱动对象
   */
  public static BufferedImage allToScreenshot(WebDriver driver) throws IOException {
    BufferedImage bi = new AShot().shootingStrategy(ShootingStrategies.viewportPasting(300))
        .takeScreenshot(driver).getImage();
    return bi;
  }

  /**
   * 《天下无赖》
   *
   * @param args
   * @throws InterruptedException
   */
  public static void main1(String[] args) throws InterruptedException {
    int threadNum = 20;
    //需要下载的图片路径
    List<String> imageUrls = new LinkedList<String>();
    //图片类型
    List<String> imageTYpe = imageType();
    //线程池
    ExecutorService executorService = new ThreadPoolExecutor(0, threadNum, 20L, TimeUnit.SECONDS,
        new ArrayBlockingQueue<Runnable>(1000));
    //设置驱动参数信息
    WebDriver webDriver = new ChromeDriver(chromeOptions());
    //设置devTools
//    webDriver = devToolsOperation(webDriver, imageTYpe, imageUrls);
    webDriver.get("https://www.kuaikanmanhua.com/web/comic/9148/");
    //显式等待
    WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(10),
        Duration.ofSeconds(3));
    //机器人滚动
    System.out.println("================开启机器人==================");
    robotMouseWheel(42560L, webDriver, 6, 1000L);
    System.out.println("================关闭机器人==================");
    //下载图片
    System.out.println("================开始下载图片==================");
    processSync(executorService, imageUrls, dirPath);
    System.out.println("================完成下载图片==================");

    Thread.sleep(2000);

    webDriver.close();
  }

  /**
   * AShot截图
   *
   * @param webDriver
   * @throws IOException
   */
  public static void responseAsImage(WebDriver webDriver, int widthShifting, int heightShifting)
      throws IOException {
    webDriver.manage().window().maximize();
    //AShot截图
    BufferedImage fullImg = allToScreenshot(webDriver);
    //获取节点
    WebElement ele = webDriver.findElement(By.xpath("//div[@id=\"cp_img\"]/img[@id=\"cp_image\"]"));
    File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
    //获取ele的节点位置
    Point point = ele.getLocation();
    //获取节点的宽和高
    int eleWidth = ele.getSize().getWidth() - widthShifting * 2;
    int eleHeight = ele.getSize().getHeight() - heightShifting * 2;
    // 从节点出开始截取
    BufferedImage eleScreenshot = fullImg.getSubimage(point.getX() + widthShifting,
        point.getY() + heightShifting, eleWidth, eleHeight);

    ImageIO.write(eleScreenshot, "png", screenshot);
    // 保存到磁盘
    File screenshotLocation = new File(outFile);
    FileUtils.copyFile(screenshot, screenshotLocation);
  }

  /**
   * AShot截图 《妖神记》
   *
   * @param webDriver
   * @param widthShifting
   * @param heightShifting
   * @param pageNum
   * @param imgSuffix
   * @param
   * @throws IOException
   */
  public static void responseAsImage2(WebDriver webDriver, int widthShifting, int heightShifting,int pageNum, String imgSuffix, int nodeNum)throws IOException, InterruptedException {
    //窗口最大
    webDriver.manage().window().maximize();
    String href = "/m426535/";
    Boolean start = true;
    for (int node = 0; node < nodeNum; node++) {
      if (start) {
        String url = "https://www.dm5.com" + href + "#ipg1";
        webDriver.get(url);
        start = false;
      }
      //显式等待
      WebDriverWait webDriverWait = new WebDriverWait(webDriver, Duration.ofSeconds(10),
          Duration.ofSeconds(5));
      for (int i = 1; i < pageNum + 1; i++) {
        System.out.println("=========pageNum:" + i + "===========");
        Thread.sleep(2000);
        //AShot截图
        BufferedImage fullImg = allToScreenshot(webDriver);
        //获取节点
        WebElement ele = webDriver.findElement(
            By.xpath("//div[@id=\"cp_img\"]/img[@id=\"cp_image\"]"));
        File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        //获取ele的节点位置
        Point point = ele.getLocation();
        //获取节点的宽和高
        int eleWidth = ele.getSize().getWidth() - widthShifting * 2;
        int eleHeight = ele.getSize().getHeight() - heightShifting * 2;
        // 从节点出开始截取
        BufferedImage eleScreenshot = fullImg.getSubimage(point.getX() + widthShifting,
            point.getY() + heightShifting, eleWidth, eleHeight);
        ImageIO.write(eleScreenshot, "png", screenshot);
        // 保存到磁盘
        if (href.length() > 9) {
          href = href.substring(href.length()-9);
          System.out.println("href.substring:" + href);
        }
        File screenshotLocation = new File(outFile + href.substring(0, href.length() - 1));
        screenshotLocation.mkdirs();
        File targetPath = new File(outFile + href + "image" + i + imgSuffix);
        System.out.println("=========targetPath:" + targetPath + "=============");
        FileUtils.copyFile(screenshot, targetPath);

        Thread.sleep(2000);
        if (i != pageNum) {
          //表达式获取数据
          WebElement until = webDriverWait.until(
              ExpectedConditions.visibilityOfElementLocated(By.xpath("//a[text()=\"下一页\"]"))
          );
          until.click();
        } else {
          //表达式获取数据
          WebElement until = webDriverWait.until(
              ExpectedConditions.visibilityOfElementLocated(By.xpath("//a[text()=\"下一章\"]"))
          );
          href = until.getAttribute("href");
          until.click();
          System.out.println("++++++href:++++++" + href);
        }
      }
    }
  }

  /**
   * 代码定位 进行下滑
   *
   * @param webDriver
   * @param pageNum   页数
   * @throws InterruptedException
   */
  public static void pageNext2(WebDriver webDriver, int pageNum) throws InterruptedException {
    //高度
    System.out.println("====================");
    for (int i = 1; i < pageNum; i++) {
      System.out.println("=========pageNum:" + i + "===========");
      //表达式获取数据
      webDriver.findElement(By.xpath("//a[text()=\"下一页\"]")).click();
      Thread.sleep(2000);
    }
  }

  /**
   * 设置devTools
   *
   * @param webDriver
   * @param imageTYpe
   * @param imageUrls
   * @return
   */
  public static WebDriver devToolsOperation(WebDriver webDriver, List<String> imageTYpe,
      List<String> imageUrls) {
    webDriver = new Augmenter().augment(webDriver);
    DevTools devTools = ((HasDevTools) webDriver).getDevTools();
    devTools.createSession();
    devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    // 获取Request信息
    devTools.addListener(Network.requestWillBeSent(), res -> {
      if (imageTYpe.contains(res.getRequest().getHeaders().get("Sec-Fetch-Dest")) ||
          imageTYpe.contains(res.getRequest().getHeaders().get("content-type"))) {
        System.out.println("requestWillBeSent: " + res.getRequest().getUrl());
      }
    });
    // 获取Response信息
    WebDriver finalWebDriver = webDriver;
    devTools.addListener(Network.responseReceived(), res -> {
      if (imageTYpe.contains(res.getResponse().getHeaders().get("content-type")) ||
          imageTYpe.contains(res.getResponse().getMimeType())) {
        imageUrls.add(res.getResponse().getUrl());
        System.out.println("url: " + res.getResponse().getUrl());
      }
    });

    // 获取Response响应内容
//        devTools.addListener(Network.responseReceived(), res -> {
//            // 获取network 请求的responseBody
//            String responseBody = devTools.send(Network.getResponseBody(res.getRequestId())).getBody();
//            System.out.println("responseReceived: "+res.getResponse().getUrl());
//        });

    //窗口最大化
    webDriver.manage().window().maximize();
    return webDriver;
  }

  /**
   * 设置图片类型
   *
   * @return
   */
  public static List<String> imageType() {
    //图片类型
    List<String> imageTYpe = new ArrayList<>();
    imageTYpe.add("image/jpeg");
    imageTYpe.add("image/jpg");
    imageTYpe.add("image/png");
    imageTYpe.add("image");
    imageTYpe.add("png");
    imageTYpe.add("jpg");
    imageTYpe.add("jpeg");
    return imageTYpe;
  }

  /**
   * 设置驱动参数信息
   *
   * @return
   */
  public static ChromeOptions chromeOptions() {
    // 设置webdirver路径  这个BrushTicket是指的这个代码所在的类。
    System.setProperty("webdriver.chrome.driver", "D:\\chromdriver\\chromedriver2.exe");
    // 创建ChromeOptions，options可以设置一些网页请求头啥的
    ChromeOptions options = new ChromeOptions();
    // 指定本机chrome安装位置
    options.setBinary("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
    // 无浏览器模式
    //        options.addArguments("--headless");
    // 为了让root用户也能执行
    options.addArguments("--no-sandbox");
    // 设置屏蔽
    options.addArguments("--disable-blink-features=AutomationControlled");
    // 最大化运行（全屏窗口）,不设置，取元素会报错
    options.addArguments("'--start-maximized");
    //传下面参数来禁止掉谷歌受自动化控制的信息栏
    options.setExperimentalOption("excludeSwitches",
        Collections.singletonList("enable-automation"));
    //设置为 headless 模式避免报错用的参数
    options.addArguments("--disable-gpu");
    return options;
  }

  /**
   * @param webDriver
   * @param wheelAmt
   * @param randomSeed 随机秒
   * @throws InterruptedException
   */
  public static void robotMouseWheel(Long height, WebDriver webDriver, int wheelAmt,
      Long randomSeed) throws InterruptedException {
    //高度
    if (ObjectUtil.isNull(height) || height == 0L) {
      height = (long) ((JavascriptExecutor) webDriver).executeScript(
          "return document.documentElement.scrollHeight");
    }
    System.out.println("+++++++++++++++height: " + height + "++++++++++++++++");
    //一个滚轮80像素
    int splitNum = 80 * wheelAmt;
    int pageNum = (int) (height % splitNum == 0 ? height / splitNum : height / splitNum + 1);
    for (int i = 1; i < pageNum + 1; i++) {
      System.out.println("++++++++++++" + (i * splitNum) + "+++++++++++++++");
      //wheelAmt代表滚轮一个卡槽 80像素
      RobotUtil.setDelay(Math.toIntExact(randomSeed));
      RobotUtil.mouseWheel(wheelAmt);
      //临时休眠
      Thread.sleep(randomSeed);
    }
  }

  /**
   * @param webDriver
   * @param wheelAmt
   * @param randomSeed 随机秒
   * @throws InterruptedException
   */
  public static void robotMouseWheel2(Long height, WebDriver webDriver, int wheelAmt,Long randomSeed) throws InterruptedException, IOException {
    webDriver.manage().window().maximize();
    //高度
    if (ObjectUtil.isNull(height) || height == 0L) {
      height = (long) ((JavascriptExecutor) webDriver).executeScript(
          "return document.documentElement.scrollHeight");
    }
    System.out.println("+++++++++++++++height: " + height + "++++++++++++++++");
    //一个滚轮80像素
    int splitNum = 80 * wheelAmt;
    int pageNum = (int) (height % splitNum == 0 ? height / splitNum : height / splitNum + 1);
    for (int i = 1; i < pageNum + 1; i++) {
      System.out.println("++++++++++++" + (i * splitNum) + "+++++++++++++++");
      //wheelAmt代表滚轮一个卡槽 80像素
      RobotUtil.setDelay(Math.toIntExact(randomSeed));
      RobotUtil.mouseWheel(wheelAmt);
      //临时休眠
      Thread.sleep(randomSeed);
    }
    BufferedImage fullImg = RobotUtil.captureScreen();
    ImageIO.write(fullImg, "png", new File("D:\\ChromeDown\\downloadimage\\test.png"));
  }

  /**
   * 代码定位 进行下滑
   *
   * @param webDriver
   * @param splitNum  滚轮一次分割的像素
   * @throws InterruptedException
   */
  public static void windowScrollTo(WebDriver webDriver, int splitNum) throws InterruptedException {
    //高度
    long height = (long) ((JavascriptExecutor) webDriver).executeScript(
        "return document.documentElement.scrollHeight");
    System.out.println("====================" + height);
    //1080 - 142 - 40 = 898 900
    int pageNum = (int) (height % splitNum == 0 ? height / splitNum : height / splitNum + 1);
    for (int i = 1; i < pageNum + 1; i++) {
      String executeScript = "";
      if (i == pageNum) {
        //下拉到页面指定位置
        executeScript =
            "window.scrollTo(" + ((int) (i - 1) * splitNum) + "," + ((int) height - (i * splitNum))
                + ")";
      } else {
        executeScript = "window.scrollTo(" + (i - 1) * splitNum + "," + i * splitNum + ")";
      }
      System.out.println("====================" + executeScript);
      ((JavascriptExecutor) webDriver).executeScript(executeScript);
      //表达式获取数据
//            WebElement element = webDriver.findElement(By.xpath(""));
      Thread.sleep(2000);
    }
  }

  /**
   * 代码定位 进行下滑
   *
   * @param webDriver
   * @param pageNum   页数
   * @throws InterruptedException
   */
  public static void pageNext(WebDriver webDriver, int pageNum) throws InterruptedException {
    //高度
    long height = (long) ((JavascriptExecutor) webDriver).executeScript(
        "return document.documentElement.scrollHeight");
    System.out.println("====================" + height);
    for (int i = 1; i < pageNum; i++) {
      //表达式获取数据
      webDriver.findElement(By.xpath("//a[text()=\"下一页\"]")).click();
      Thread.sleep(2000);
    }
  }

  /**
   * 多线程处理
   *
   * @param executorService
   * @param dirPath
   */
  public static void processSync(ExecutorService executorService, List<String> imageUrls,
      String dirPath) {
    File file = new File(dirPath);
    file.mkdirs();
    //随机下载时间
    Random random = new Random(5);
    for (int i = 0; i < imageUrls.size(); i++) {
      String imagePath = dirPath + "\\" + "image" + i + ".jpg";
      String imageUrl = imageUrls.get(i);
      executorService.execute(() -> downloaderMothod(imageUrl, imagePath));
    }
    executorService.shutdown();
  }

  /**
   * 下载方法
   *
   * @param url
   * @param name
   */
  public static void downloaderMothod(String url, String name) {
    try {
//      Thread.sleep(randomNum);
      FileUtils.copyURLToFile(new URL(url), new File(name));
    } catch (IOException e) {
      e.fillInStackTrace();
      System.out.println("IO异常，downloaderMothod方法异常");
    }
  }
}
